/*
 * Animation.cpp
 *
 *	Author: stravant
 *	Description:
 *		
 */

#include "Animation.h"

namespace tbt {

Animation::Animation(): mRunning(false), mDelegate(0), TickerPeriodic(TimeDelta::FromMilliseconds(30)) {
}

Animation::Animation(AnimationDelegate* delegate): mRunning(false), mDelegate(delegate),
		TickerPeriodic(TimeDelta::FromMilliseconds(30)) {
}

Animation::~Animation() {
	//
}

void Animation::start() {
	if (!mRunning) {
		mTimer.reset();
		mRunning = true;
		animationStarted();
		TickerPeriodic::start();
	}
}

void Animation::stop() {
	if (mRunning) {
		mRunning = false;
		animationStopped();
		if (mDelegate) {
			if (shouldStopSendCancel()) {
				mDelegate->animationCanceled(this);
			} else {
				mDelegate->animationEnded(this);
			}
		}
		TickerPeriodic::stop();
	}
}

void Animation::setFramerate(int fps) {
	double secondsPerFrame = (1.0/static_cast<double>(fps));
	setPeriod(TimeDelta::FromMicroseconds(static_cast<int>(secondsPerFrame*Time::kMicrosecondsPerSecond)));
}

void Animation::periodicTick(Time time) {
	if (mRunning) {
		animationStep(mTimer.elapsed());
		if (mDelegate)
			mDelegate->animationProgressed(this);
	}
}

/////////////////////////////////////////

AnimationLinear::AnimationLinear(AnimationDelegate* delegate):
	Animation(delegate), mCurrent(0.0), mFrom(0.0), mTo(0.0), mRate(0.0) {}

AnimationLinear::~AnimationLinear() {}

void AnimationLinear::setTween(double from, double to, double rate) {
	mCurrent = mFrom = from;
	mTo = to;
	mRate = rate;
}

void AnimationLinear::animationStarted() {
	mLastElapsed = TimeDelta();
	mCurrent = mFrom;
}

void AnimationLinear::animationStopped() {
	mCurrent = mTo;
}

void AnimationLinear::animationStep(TimeDelta elapsed) {
	//how much to change by
	double delta = (elapsed-mLastElapsed).inSecondsF()*mRate;
	mLastElapsed = elapsed;

	//move towards endpoint
	if (mTo > mFrom) {
		mCurrent += delta;
		if (mCurrent >= mTo) {
			mCurrent = mTo;
			animateLinear(mCurrent);
			Animation::stop();
		} else {
			animateLinear(mCurrent);
		}
	} else {
		mCurrent -= delta;
		if (mCurrent <= mTo) {
			mCurrent = mTo;
			animateLinear(mCurrent);
			Animation::stop();
		} else {
			animateLinear(mCurrent);
		}
	}
}

///////////////////////////////////////////

AnimationSlide::AnimationSlide(TimeDelta duration, AnimationDelegate* delegate):
	AnimationLinear(delegate), mSlideState(kSlideHide) {
	mSlideDuration = duration;
	mSlideRate = 1.0/mSlideDuration.inSecondsF();
}

AnimationSlide::~AnimationSlide() {}

void AnimationSlide::slideShow() {
	if (mSlideState == kSlideHide) { //show it
		mSlideState = kSlideShow;
		if (isRunning()) { //hiding, reverse the animation
			double cur = getCurrentValue(); //[0-1] value
			setTween(cur, 1.0, mSlideRate);
		} else { //hidden, just start showing
			setTween(0.0, 1.0, mSlideRate);
			Animation::start();
		}
	}
}

void AnimationSlide::slideHide() {
	if (mSlideState == kSlideShow) {
		mSlideState = kSlideHide;
		if (isRunning()) {
			double cur = getCurrentValue();
			setTween(cur, 0.0, mSlideRate);
		} else {
			setTween(1.0, 0.0, mSlideRate);
			Animation::start();
		}
	}
}

/////////////////////////////////////////

}
































